/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2014 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_VIEWPORT_H
#define SX_VIEWPORT_H

#include <sxComponent.h>
#include <sxRectangle.h>
#include <sxPosition2D.h>
#include <sxColor3.h>
#include <sxColor4.h>

using Sx::Graphics::Color3f;
using Sx::Graphics::Color4f;

namespace Sx {
namespace Interface {

class ViewportController;

class Viewport : public Component {
public:
	Viewport(unsigned int fps = 60u);
	virtual ~Viewport();

	virtual bool initialize() = 0;
	virtual void update(float dt) = 0;
	virtual void render() const = 0;
	virtual void resize(int width, int height) = 0;

	bool setController(const std::shared_ptr<ViewportController>& controller);
	std::shared_ptr<ViewportController> getController() const;

	/* 
	 * If user updates is set to true then when the user interacts with the
	 * viewport (causing some event) it will be redrawn.
	 */
	void enableUserUpdates(bool b = true);
	void disableUserUpdates();

	bool setClearColor(const Color3f& color);
	bool setClearColor(const Color4f& color);
	bool setClearColor(float r, float g, float b);
	bool setClearColor(float r, float g, float b, float a);

	virtual void setRealtime(bool realtime = true);
	bool isRealtime() const;

	void setWarpCursor(bool warp);
	bool hasCursorWarp() const;

	virtual bool setFramesPerSecond(unsigned int fps);
	unsigned int getFramesPerSecond() const;

	/*
	 * This function can be inserted into a mouse-move callback to make the
	 * cursor wrap from one side of this viewport to the other.
	 *
	 * This functionality is generally used for simulating 'infinite' mouse
	 * movement for interacting with rendered scenes. If the cursor needs to
	 * be moved, this function will return non-zero Position2D values. This will
	 * indicate the displacement that needs to be applied to the current cursors
	 * position.
	 */
	Graphics::Position2Di calculateCursorWarpDisplacement(int cursorX, int cursorY);

	/* 
	 * Given a desired frame-rate, determine the number of milliseconds between
	 * each frame.
	 */
	static float CalculateMillisecondIncrement(unsigned int fps);
	static float CalculateNanosecondIncrement(unsigned int fps);

	static const unsigned int CURSOR_WARP_THRESHOLD = 10;

protected:
	std::shared_ptr<ViewportController> controller;

	/*
	 * Allows the cursor to warp from one side to the other (or top to bottom)
	 * when the user moves the cursor. This removes the problem of the cursor
	 * 'hitting' the edge of the screen and is useful for some input operations.
	 */
	bool warpCursor;

	/*
	 * Determines if a viewport can have time-based events that trigger this
	 * viewport to render (redraw). If a viewport is set to realtime then a
	 * timer should render its contents on a consistent timer.
	 *
	 * TLDR:
	 *   True: Timer controls when the viewport is redrawn
	 *   False: Events control when the viewport is redrawn
	 */
	bool realtime;

	/* 
	 * This viewport will be updated (redrawn) based on when the user creates
	 * an event that the viewport responds to. When the event is handled the
	 * viewport will be redrawn.
	 * 
	 * TLDR: 
	 *   True: User generated events (such as mouse events) cause a redraw
	 *   False: No update events (unless realtime is used)
	 */
	bool userUpdates;

	/* 
	 * If this viewport is timeDriven (render calls are based on a timer) then
	 * this viewports update (render) frequency will be defined by the number
	 * of frames-per-second. (Typically 24, 30, 60, etc.)
	 */
	unsigned int framesPerSecond;
};

}

}

#endif
